/*! ----------------------------------------------------------------------------
 * @file	deca_spi.c
 * @brief	SPI access functions
 *
 * @attention
 *
 * Copyright 2015 (c) DecaWave Ltd, Dublin, Ireland.
 *
 * All rights reserved.
 *
 * @author DecaWave
 */
#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
#include <stdint.h>  
#include <unistd.h>  
#include <stdlib.h>  
#include <getopt.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include <linux/types.h>  
#include <linux/spi/spidev.h> 

#include "deca_spi.h"
#include "deca_device_api.h"
#include "port.h"

static int fd;  

static void pabort(const char *s)  
{  
    perror(s);  
    abort();  
}  
  
static const char *device = "/dev/spidev0.0";  
static uint8_t mode;  
static uint8_t bits = 8;  
static uint32_t speed = 500000;  
  

void SPI_Init(char * SPIx)
{
	int ret = 0;

	fd = open(SPIx, O_RDWR);
	if (fd < 0)
		pabort("can't open device");

	 printf("open device sucucess %s, fd = %d\n", device, fd);  

	/* 
	* spi mode 
	 */  
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);  
	if (ret == -1)  
		pabort("can't set spi mode");  

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);  
	if (ret == -1)  
		pabort("can't get spi mode");  

	/* 
	 * bits per word 
	 */  
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);  
	if (ret == -1)  
		pabort("can't set bits per word");  

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);  
	if (ret == -1)  
		pabort("can't get bits per word");  

	/* 
	 * max speed hz 
	 */  
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);  
	if (ret == -1)  
		pabort("can't set max speed hz");  

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);  
	if (ret == -1)  
		pabort("can't get max speed hz");  

	printf("spi mode: %d\n", mode);  
	printf("bits per word: %d\n", bits);  
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);  
}


/*! ------------------------------------------------------------------------------------------------------------------
 * Function: openspi()
 *
 * Low level abstract function to open and initialise access to the SPI device.
 * returns 0 for success, or -1 for error
 */
int openspi(/*SPI_TypeDef* SPIx*/)
{
	// done by port.c, default SPI used is SPI01

	return 0;

} // end openspi()

/*! ------------------------------------------------------------------------------------------------------------------
 * Function: closespi()
 *
 * Low level abstract function to close the the SPI device.
 * returns 0 for success, or -1 for error
 */
int closespi(void)
{
	//while (port_SPIx_busy_sending()); //wait for tx buffer to empty

	//port_SPIx_disable();

	return 0;

} // end closespi()

/*! ------------------------------------------------------------------------------------------------------------------
 * Function: writeto_spi()
 *
 * Low level abstract function to write to the SPI
 * Takes two separate byte buffers for write header and write data
 * returns 0 for success, or -1 for error
 */
#pragma GCC optimize ("O3")
int writeto_spi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       bodyLength,
    const uint8 *bodyBuffer
)
{
	unsigned char  buf[128] = {0};
	unsigned char  rx_buf[128] = {0};

	struct spi_ioc_transfer mesg[1];

	int retval = 0;
	int i = 0, index = 0;

	memset(mesg, 0, sizeof(struct spi_ioc_transfer));

	mesg[0].tx_buf = (__u32)buf;
	mesg[0].rx_buf = (__u32)rx_buf;
	mesg[0].len = headerLength + bodyLength;
	mesg[0].speed_hz = 500000;
	mesg[0].bits_per_word = 8;
	mesg[0].delay_usecs = 10000;

	//printf("len : %d + %d = %d\n", headerLength, bodyLength, headerLength + bodyLength);

	for (index = 0; index < headerLength; index++) {
		*(unsigned char  *)(&buf[index]) = headerBuffer[index];
	}

	for (i = 0; i < bodyLength; i++) {
		*(unsigned char  *)(&buf[index++]) = bodyBuffer[i];
	}

	printf("write buf:");
	for (i = 0; i < 0x10; i++) {
		printf(" 0x%x", *(unsigned char *)(&buf[i]));
	}
	printf("\n");

	
	retval = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);

	 if (retval < 1) 
		pabort("can't send spi message"); 
	
	return 0;
} // end writeto_spi()


/*! ------------------------------------------------------------------------------------------------------------------
 * Function: readfrom_spi()
 *
 * Low level abstract function to read from the SPI
 * Takes two separate byte buffers for write header and read data
 * returns the offset into read buffer where first byte of read data may be found,
 * or returns -1 if there was an error
 */
#pragma GCC optimize ("O3")
int readfrom_spi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       readlength,
    uint8       *readBuffer
)
{
	unsigned char  buf[128] = {0};
	unsigned char  rx_buf[128] = {0};
	struct spi_ioc_transfer mesg[1];
	int retval = 0;
	int i = 0, index = 0;

	memset(mesg, 0, sizeof(struct spi_ioc_transfer));

	mesg[0].tx_buf = (__u32)buf;
	mesg[0].rx_buf = (__u32)rx_buf;
	mesg[0].len = headerLength + readlength;
	mesg[0].speed_hz = 500000;
	mesg[0].bits_per_word = 8;
	mesg[0].delay_usecs = 10000;

	//*(unsigned char  *)(&buf[0]) = headerBuffer[0];
	//*(unsigned char  *)(&buf[1]) = headerBuffer[1];

	for (index = 0; index < headerLength; index++) {
		*(unsigned char  *)(&buf[index]) = headerBuffer[index];
	}

	#if 0
	for (i = 0; i < headerLength; i++) {
		printf("buf = 0x%x\n", *(unsigned char *)(&buf[i]));
		printf("headerBuffer = 0x%x\n", headerBuffer[i]);
	}
	#endif

	retval = ioctl(fd, SPI_IOC_MESSAGE(1), mesg);
	//printf("retval = %d\n", retval);
	if (retval < 1) 
		pabort("can't send spi message"); 

	printf("read buf:");
	for (i = 0; i < 0x10; i++) {
		printf(" 0x%x", *(unsigned char *)(&rx_buf[i]));
	}
	printf("\n");

	for (i = headerLength; i < readlength + headerLength; i++) {
		printf("read result = 0x%x\n", *(unsigned char *)(&rx_buf[i]));
		readBuffer[i-headerLength] = *(unsigned char *)(&rx_buf[i]);
	}

    return 0;
} // end readfrom_spi()



#if (EVB1000_LCD_SUPPORT == 1)

void writetoLCD
(
    uint32       bodylength,
    uint8        rs_enable,
    const uint8 *bodyBuffer
)
{

} // end writetoLCD()
#endif

